/*
 * 文件名：SmsSenderProxy.java
 * 版权：Copyright by http://www.infopub.top/
 * 描述：
 * 修改人：Awoke
 * 修改时间：2018年11月7日
 * 跟踪单号：
 * 修改单号：
 * 修改内容：
 */

package top.infopub.mgc.core.sender.sms;


import java.math.BigDecimal;
import java.util.Date;
import java.util.concurrent.Callable;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import top.infopub.cache.RedisCached;
import top.infopub.concurrent.ExecutorManager;
import top.infopub.mgc.core.service.MsgTaskService;
import top.infopub.model.mgc.MsgTask;
import top.infopub.tdp.util.BizParaUtil;
import top.infopub.util.DateUtil;
import top.infopub.util.RedisExpiresUtil;
import top.infopub.vo.ResponseVo;


/**
 * 短信发送代理
 * @author Awoke
 * @version 2018年11月7日
 * @see SmsSenderProxy
 * @since
 */
@Service
public class SmsSenderProxy {

    private static final Logger logger = LoggerFactory.getLogger(SmsSenderProxy.class);

    @Autowired
    private MsgTaskService msgTaskService;

    @Autowired
    private RedisCached redisCached;

    @Autowired
    private RedisExpiresUtil redisExpiresUtil;

    @Resource
    private SmsSenderYx smsSender;

    /** 一小时之内给用户发送短信的限制 redis-hash-key **/
    private final String MGC_TEL_HOUR_RATE_HASH = "mgc:tel.hour.rate:hash";

    /** 一天之内给用户发送短信的限制 redis-hash-key **/
    private final String MGC_TEL_DAY_RATE_HASH = "mgc:tel.day.rate:hash";

    /** 全站一小时之内给用户发送短信的限制，不限制的话设置为0 **/
    private static final String BIZ_PARA_LIMIT_HOUR_KEY = "mgc_tel_send_limit_hour";

    /** 全站一天之内给用户发送短信的限制，不限制的话设置为0 **/
    private static final String BIZ_PARA_LIMIT_DAY_KEY = "mgc_tel_send_limit_day";

    /**
     * 发送短信
     * @param msgTask 
     * @see
     */
    @SuppressWarnings("unchecked")
    public void sendMessage(final MsgTask msgTask) {
        // 消息状态 1：待发送 2：正在发送 3：发送成功 4：发送失败  //
        MsgTask uptMsgTask = new MsgTask();
        uptMsgTask.setId(msgTask.getId());
        // 正在发送
        uptMsgTask.setState(2);
        uptMsgTask.setBeginSendDatetime(new Date());
        uptMsgTask.setUpdatetime(new Date());
        msgTaskService.updateBySelective(uptMsgTask);
        // 全站发送限制
        if (!timeLimit(msgTask)) {
            logger.info("当前短信次数限制，发送失败，手机号:" + msgTask.getMsgRecipient());
            return;
        }
        ResponseVo<String> responseVo = new ResponseVo<String>(false, 9999, null);
        // 等待线程返回处理结果
        try {
            responseVo = (ResponseVo<String>)ExecutorManager.getInstance().futureTask(
                new Callable<Object>() {
                    @Override
                    public Object call()
                        throws Exception {
                        // 发送短信
                        return smsSender.sendMessage(msgTask.getMsgRecipient(),
                            msgTask.getContent());
                    }
                }, msgTask.getTimeout().multiply(new BigDecimal("60")).longValue());// 转成单位秒
        }
        catch (Exception e) {
            logger.error("", e);
            // 发送失败
            uptMsgTask.setState(4);
            uptMsgTask.setBeginSendDatetime(null);
            uptMsgTask.setUpdatetime(new Date());
            // 异常信息 
            uptMsgTask.setMsgDesc(e.getClass().getName() + " " + e.getMessage());
            msgTaskService.updateBySelective(uptMsgTask);
            // 直接return 防止后续update
            return;
        }
        if (responseVo.isSuccess()) {
            // 发送成功
            uptMsgTask.setState(3);
            uptMsgTask.setBeginSendDatetime(null);
            uptMsgTask.setUpdatetime(new Date());
            msgTaskService.updateBySelective(uptMsgTask);
            // 发送成功 才更新限制次数 
            uptMsgTask.setMsgRecipient(msgTask.getMsgRecipient());
            timeLimitUpdate(uptMsgTask);
        }
        else {
            // 发送失败
            uptMsgTask.setState(4);
            uptMsgTask.setBeginSendDatetime(null);
            uptMsgTask.setUpdatetime(new Date());
            // 异常信息 
            uptMsgTask.setMsgDesc(responseVo.getMsg());
            msgTaskService.updateBySelective(uptMsgTask);
        }
    }

    /** 更新限制次数  **/
    private void timeLimitUpdate(MsgTask msgTask) {
        try {
            // 每小时限制
            String key = getHlimitRedisKey(msgTask.getMsgRecipient());
            redisCached.hincrBy(MGC_TEL_HOUR_RATE_HASH, key, 1);
            // 每天限制
            String key2 = getDlimitRedisKey(msgTask.getMsgRecipient());
            redisCached.hincrBy(MGC_TEL_DAY_RATE_HASH, key2, 1);
        }
        catch (Exception e) {
            logger.error("", e);
        }
    }

    /** 判断是否限制 **/
    private boolean timeLimit(MsgTask msgTask) {
        Long limithourValue = 0L;
        Long limitDayValue = 0L;
        try {
            limithourValue = Long.parseLong(BizParaUtil.get(BIZ_PARA_LIMIT_HOUR_KEY));
            limitDayValue = Long.parseLong(BizParaUtil.get(BIZ_PARA_LIMIT_DAY_KEY));
        }
        catch (NumberFormatException e) {
            logger.error("全站短信发送按次数限制，解析出错", e);
        }
        // 为0不限制  每小时
        if (limithourValue > 0) {
            try {
                String mapkey = getHlimitRedisKey(msgTask.getMsgRecipient());
                // 当前发送次数 
                long count = redisCached.hgetLong(MGC_TEL_HOUR_RATE_HASH, mapkey);
                if (count == 0) {
                    redisExpiresUtil.zaddAndHsetLong(MGC_TEL_HOUR_RATE_HASH, mapkey, 1L,
                        60 * 60 * 1000);
                }
                else {
                    if (count >= limithourValue + 1) {
                        msgTask.setUpdatetime(new Date());
                        msgTask.setState(4);
                        msgTask.setMsgDesc("发送短信失败，原因：超过1小时内最大次数限制。限制次数为:" + limithourValue
                                           + "，当前发送次数为:" + count);
                        msgTaskService.updateBySelective(msgTask);
                        logger.error("发送短信失败，原因：超过1小时内最大次数限制。限制次数为:" + limithourValue
                                     + "，当前发送次数为:" + count);
                        return false;
                    }
                }
            }
            catch (Exception e) {
                logger.error("按小时限制出错，按照默认不限制处理", e);
            }
        }
        // 为0不限制  每天
        if (limitDayValue > 0) {
            try {
                String mapkey = getDlimitRedisKey(msgTask.getMsgRecipient());
                // 当前发送次数 
                long count = redisCached.hgetLong(MGC_TEL_DAY_RATE_HASH, mapkey);
                if (count == 0) {
                    redisExpiresUtil.zaddAndHsetLong(MGC_TEL_DAY_RATE_HASH, mapkey, 1L,
                        60 * 60 * 24 * 1000);
                }
                else {
                    if (count >= limitDayValue + 1) {
                        msgTask.setUpdatetime(new Date());
                        msgTask.setState(4);
                        msgTask.setMsgDesc("发送短信失败，原因：超过1天内超过的最大次数限制。限制次数为:" + limitDayValue
                                           + "，当前发送次数为:" + count);
                        msgTaskService.updateBySelective(msgTask);
                        msgTask.setMsgDesc("发送短信失败，原因：超过1天内超过的最大次数限制。限制次数为:" + limitDayValue
                                           + "，当前发送次数为:" + count);
                        return false;
                    }
                }
            }
            catch (Exception e) {
                logger.error("按天限制出错，按照默认不限制处理", e);
            }
        }
        return true;
    }

    /** redisKey hash mapkey **/
    private String getHlimitRedisKey(String mobile) {
        String str = DateUtil.currentDate("yyyyMMddHH");
        return mobile + ":" + str;
    }

    /** redisKey hash mapkey **/
    private String getDlimitRedisKey(String mobile) {
        String str = DateUtil.currentDate("yyyyMMdd");
        return mobile + ":" + str;
    }

}
